//
// Created by martin on 2/18/22.
//

#ifndef MUDUO_CONNECTOR_H
#define MUDUO_CONNECTOR_H

#include "muduo/base/noncopyable.h"
#include "muduo/net/InetAddress.h"
#include "muduo/net/Channel.h"
#include "muduo/net/Callbacks.h"

#include <functional>
#include <memory>

namespace muduo
{
namespace net
{

class EventLoop;

/**
 * Launch a connection request to TCP Server.
 * basic call is connect(2)
 */
class Connector : noncopyable,
        public std::enable_shared_from_this<Connector>
{
public:
    typedef std::function<void (int sockfd)> NewConnectionCallback;

    Connector(EventLoop* loop, const InetAddress& serverAddr);
    ~Connector();

    void setNewConnectionCallback(const NewConnectionCallback& cb)
    { newConnectionCallback_ = cb; }

    void start();   // can be called in any thread
    void restart(); // must be called in loop thread
    void stop();    // can be called in any thread

    const InetAddress& serverAddress() const { return serverAddr_; }

private:
    enum States { kDisconnected, kConnecting, kConnected };
    static const int kMaxRetryDelayMs = 30 * 1000; // 30 sec
    static const int kInitRetryDelayMs = 500; // 500 ms

    void setState(States s) { state_ = s; }
    void startInLoop();
    void stopInLoop();
    void connect();
    void connecting(int sockfd);
    void handleWrite();
    void handleError();
    void retry(int sockfd);
    int removeAndResetChannel();
    void resetChannel();

    EventLoop* loop_;
    InetAddress serverAddr_;
    bool connect_; // atomic
    States state_;
    std::unique_ptr<Channel> channel_;
    NewConnectionCallback newConnectionCallback_;
    int retryDelayMs_;
};

} // namespace net
} // namespace muduo

#endif //MUDUO_CONNECTOR_H
